package app

import (
	"fmt"
	"time"

	nexport "nggs/export"
)

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const ConfigName = "app"

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
type ServiceConfig struct {
	Name string
	ID   int
}

func NewServiceConfig() *ServiceConfig {
	return &ServiceConfig{}
}

func (cfg ServiceConfig) GetName() string {
	return cfg.Name
}

func (cfg ServiceConfig) GetID() int {
	return cfg.ID
}

func (cfg ServiceConfig) Clone() nexport.IServiceConfigInApp {
	n := &ServiceConfig{}
	*n = cfg
	return n
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
type Config struct {
	ID                       nexport.AppID
	PprofIP                  string           // pprof监听IP，禁止用公网IP
	PprofPort                int              // pprof监听端口
	EndpointIP               string           // RPC监听IP，禁止用公网IP
	EndpointPort             int              // RPC监听端口
	Services                 []*ServiceConfig // 承载的服务，按顺序启动
	LogDir                   string           // 日志目录
	StartServiceIntervalMSec time.Duration    // 启动服务的间隔毫秒
	StopServiceIntervalMSec  time.Duration    // 停止服务的间隔毫秒
	ExitWaitSec              time.Duration    // 进程退出等待秒数
}

func NewConfig() *Config {
	return &Config{
		ID:                       0,
		PprofIP:                  "",
		PprofPort:                0,
		EndpointIP:               "",
		EndpointPort:             0,
		Services:                 nil,
		LogDir:                   "",
		StartServiceIntervalMSec: 100 * time.Millisecond,
		StopServiceIntervalMSec:  100 * time.Millisecond,
		ExitWaitSec:              5 * time.Second,
	}
}

func (c *Config) TidyAndCheck() error {
	if c.ID <= 0 {
		return fmt.Errorf("invalid ID")
	}

	if len(c.Services) == 0 {
		return fmt.Errorf("Services is empty")
	}

	if c.StartServiceIntervalMSec > 0 {
		if c.StartServiceIntervalMSec < 100 {
			return fmt.Errorf("StartServiceIntervalMSec must >= 100")
		}
	} else {
		c.StartServiceIntervalMSec = 100
	}
	c.StartServiceIntervalMSec = c.StartServiceIntervalMSec * time.Millisecond

	if c.StopServiceIntervalMSec > 0 {
		if c.StopServiceIntervalMSec < 100 {
			return fmt.Errorf("StopServiceIntervalMSec must >= 100")
		}
	} else {
		c.StopServiceIntervalMSec = 100
	}
	c.StopServiceIntervalMSec = c.StopServiceIntervalMSec * time.Millisecond

	if c.ExitWaitSec > 0 {
		if c.ExitWaitSec < 5 {
			return fmt.Errorf("ExitWaitSecond must >= 5")
		}
	} else {
		c.ExitWaitSec = 5
	}
	c.ExitWaitSec = c.ExitWaitSec * time.Second

	return nil
}

func (c Config) GetID() nexport.AppID {
	return c.ID
}

func (c *Config) SetID(id nexport.AppID) {
	c.ID = id
}

func (c Config) GetPprofIP() string {
	return c.PprofIP
}

func (c *Config) SetPprofIP(pprofIP string) {
	c.PprofIP = pprofIP
}

func (c Config) GetPprofPort() int {
	return c.PprofPort
}

func (c *Config) SetPprofPort(pprofPort int) {
	c.PprofPort = pprofPort
}

func (c Config) GetEndpointIP() string {
	return c.EndpointIP
}

func (c *Config) SetEndpointIP(endpointIP string) {
	c.EndpointIP = endpointIP
}

func (c Config) GetEndpointPort() int {
	return c.EndpointPort
}

func (c *Config) SetEndpointPort(endpointPort int) {
	c.EndpointPort = endpointPort
}

func (c *Config) EachServiceConfig(fn func(i int, serviceConfig nexport.IServiceConfigInApp) (continued bool)) {
	if fn == nil {
		return
	}
	for i, cfg := range c.Services {
		if !fn(i, cfg) {
			break
		}
	}
}

func (c *Config) GetServiceConfigByIndex(index int) (serviceConfig nexport.IServiceConfigInApp, ok bool) {
	for i, cfg := range c.Services {
		if i == index {
			ok = true
			serviceConfig = cfg
			return
		}
	}
	return
}

func (c *Config) AddServiceConfig(serviceConfig nexport.IServiceConfigInApp) {
	c.Services = append(c.Services, serviceConfig.(*ServiceConfig))
}

func (c Config) GetLogDir() string {
	return c.LogDir
}

func (c *Config) SetLogDir(logDir string) {
	c.LogDir = logDir
}

func (c Config) GetStartServiceIntervalMSec() time.Duration {
	return c.StartServiceIntervalMSec
}

func (c *Config) SetStartServiceIntervalMSec(startServiceIntervalMSec time.Duration) {
	c.StartServiceIntervalMSec = startServiceIntervalMSec
}

func (c Config) GetStopServiceIntervalMSec() time.Duration {
	return c.StopServiceIntervalMSec
}

func (c *Config) SetStopServiceIntervalMSec(stopServiceIntervalMSec time.Duration) {
	c.StopServiceIntervalMSec = stopServiceIntervalMSec
}

func (c Config) GetExitWaitSec() time.Duration {
	return c.ExitWaitSec
}

func (c *Config) SetExitWaitSec(exitWaitSecond time.Duration) {
	c.ExitWaitSec = exitWaitSecond
}

func (c Config) Clone() nexport.IServiceConfig {
	n := &Config{}
	*n = c
	n.Services = nil
	for _, serviceConfig := range c.Services {
		n.Services = append(n.Services, serviceConfig.Clone().(*ServiceConfig))
	}
	return n
}
